﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;


namespace StaticFilesServer
{
    class Program
    {
        //根目录
        static string RootPath = System.Environment.CurrentDirectory;
        //端口
        static string Port = GetSetting("port") ?? "80";
        //Mime类型映射
        static Dictionary<string, string> MimeMaps = new Dictionary<string, string>();


        [STAThread]
        static void Main(string[] args)
        {
            try
            {
                //加载MimeMap;
                LoadMimeMaps();

                var url = "http://localhost:" + Port + "/";
                var httpListenner = new HttpListener();
                httpListenner.AuthenticationSchemes = AuthenticationSchemes.Anonymous;
                httpListenner.Prefixes.Add(url);
                httpListenner.Start();
                Console.WriteLine("服务已启动：{0}", url);

                //打开浏览器
                System.Diagnostics.Process.Start(url);
                new Thread(new ThreadStart(delegate
                {
                    try
                    {
                        LoopHandle(httpListenner);
                    }
                    catch (Exception exp)
                    {
                        Console.WriteLine(exp);
                    }
                })).Start();
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp);
            }
        }

        /// <summary>
        /// 循环处理请求
        /// </summary>
        /// <param name="httpListenner"></param>
        private static void LoopHandle(HttpListener httpListenner)
        {
            while (true)
            {
                HttpListenerContext context = httpListenner.GetContext();
                HttpListenerRequest request = context.Request;
                HttpListenerResponse response = context.Response;

                var file = request.Url.LocalPath.Replace('/', '\\');
                var path = RootPath + file;

                response.ContentEncoding = Encoding.UTF8;
                if (File.Exists(path))
                {
                    HandleFile(response, path);
                }
                else if (Directory.Exists(path))
                {
                    HandleDirectory(request, response, path);
                }
                else
                {
                    HandleNotFound(response, path);
                }
                response.Close();
            }
        }

        /// <summary>
        /// 处理文件请求
        /// </summary>
        /// <param name="response"></param>
        /// <param name="path"></param>
        private static void HandleFile(HttpListenerResponse response, string path)
        {
            response.ContentType = GetContentType(path);
            var buffer = File.ReadAllBytes(path);
            response.OutputStream.Write(buffer, 0, buffer.Length);
        }

        /// <summary>
        /// 处理文件夹请求
        /// </summary>
        /// <param name="request"></param>
        /// <param name="response"></param>
        /// <param name="path"></param>
        private static void HandleDirectory(HttpListenerRequest request, HttpListenerResponse response, string path)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<html>");
            sb.Append("<head>");
            sb.Append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>");

            sb.Append("<title>dir</title>");
            sb.Append("</head>");
            sb.Append("<body>");

            sb.Append("<ul>");
            var dirList = Directory.GetDirectories(path);
            foreach (var dir in dirList)
            {
                var vdir = Path.GetFileName(dir);
                sb.AppendFormat("<li><a href='{0}'><b>{1}</b></a></li>", Path.Combine(request.Url.LocalPath, vdir), vdir);
            }

            var fileList = Directory.GetFiles(path);
            foreach (var f in fileList)
            {
                var vf = Path.GetFileName(f);
                if (!vf.StartsWith("StaticFilesServer.exe"))
                {
                    sb.AppendFormat("<li><a href='{0}'>{1}</a></li>", Path.Combine(request.Url.LocalPath, vf), vf);
                }
            }
            sb.Append("</ul>");
            sb.Append("</body>");
            sb.Append("</html>");
            response.ContentType = "text/html";
            var buffer = Encoding.UTF8.GetBytes(sb.ToString());
            response.OutputStream.Write(buffer, 0, buffer.Length);
        }


        /// <summary>
        /// 处理404
        /// </summary>
        /// <param name="response"></param>
        /// <param name="path"></param>
        private static void HandleNotFound(HttpListenerResponse response, string path)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<html>");
            sb.Append("<head>");
            sb.Append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>");

            sb.Append("<title>404</title>");
            sb.Append("</head>");
            sb.Append("<body>");
            sb.AppendFormat("<h3>没有找到文件：{0}</h3>", path);
            sb.Append("</body>");
            sb.Append("</html>");
            response.ContentType = "text/html";
            var buffer = Encoding.UTF8.GetBytes(sb.ToString());
            response.OutputStream.Write(buffer, 0, buffer.Length);
        }

        /// <summary>
        /// 得到请求内容的ContentType
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private static string GetContentType(string path)
        {
            var ext = Path.GetExtension(path).ToLower();

            string mime;
            if (MimeMaps.TryGetValue(ext, out mime))
            {
                return mime;
            }
            else
            {
                return "";
            }
        }

        /// <summary>
        /// 加载MimeMaps
        /// </summary>
        private static void LoadMimeMaps()
        {
            var value = GetSetting("mimeMaps");
            var lines = value.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);

            foreach (var line in lines)
            {
                var one = line.Replace(" ", "").Replace(" ", "").ToLower();
                if (one.Length > 0)
                {
                    var part = one.Split(new string[] { "=>" }, StringSplitOptions.RemoveEmptyEntries);
                    MimeMaps[part[0]] = part[1];
                }
            }
        }

        private static string GetSetting(string key)
        {
            var value = System.Configuration.ConfigurationManager.AppSettings.Get(key);
            return value;
        }
    }
}
